﻿#include "TranslateCommand.h"

#include <fast_io/fast_io_crypto.h>
#include <fast_io/fast_io_device.h>

#include "../../../Memory/GameData.h"

#include <json/nlohmannjson.h>
#include <thread>

std::uint_least64_t appid{};
std::u8string key{};
std::u8string local_from{u8"auto"};
std::u8string local_to{u8"en"};
std::u8string server_from{u8"auto"};
std::u8string server_to{u8"en"};

std::u8string translate(std::u8string_view str, bool isserver) noexcept {
	try {
		int salt{rand()};  // 生成随机数

		fast_io::md5_context ctx{};
		std::u8string sign{fast_io::u8concat(appid, str, salt, key)};
		fast_io::transmit(fast_io::manipulators::as_file(ctx), fast_io::u8ibuffer_view{sign});
		ctx.do_final();  // 生成验证

		fast_io::u8iobuf_socket_file socket(fast_io::tcp_connect(fast_io::ipv4{{180, 101, 49, 58}, 80}));  // 连网

		print(socket,
			  u8"GET /api/trans/vip/translate?q=",
			  Utils::Utils::escapeURL(str),
			  u8"&from=",
			  isserver ? server_from : local_from,
			  u8"&to=",
			  isserver ? server_to : local_to,
			  u8"&appid=",
			  appid,
			  u8"&salt=",
			  salt,
			  u8"&sign=",
			  fast_io::mnp::hash_digest(ctx),
			  u8" HTTP/1.1\r\n"
			  "Host:api.fanyi.baidu.com\r\n"
			  "User-agent:whatever\r\n"
			  "Accept-Type:*/*\r\n"
			  "Connection:close\r\n\r\n");  // 发送请求头

		fast_io::u8http_header_buffer buffer{};
		scan(socket, buffer);
		using namespace std::string_view_literals;
		for (auto [key, value] : line_generator(buffer)) {
			if (std::u8string_view(key) == u8"Content-Length"sv) [[unlikely]] {
				auto content_length{::fast_io::u8to<std::uint_least64_t>(value)};  // 读取出长度

				std::u8string jsontemp{};
				scan(socket, fast_io::mnp::line_get(jsontemp));  // json格式文件
				if (isserver) {
					try {
						nlohmann::json js = nlohmann::json::parse(*reinterpret_cast<std::string*>(&jsontemp));
						if (js.at("from").get<std::string>() == js.at("to").get<std::string>())
							return std::u8string{};
					} catch (const std::exception&) {
						return std::u8string{};
					}
				} 

				jsontemp.resize(content_length - 4);
				auto i = jsontemp.find(u8",\"dst\":\"");
				if (i == std::u8string::npos)
					break;
				jsontemp.erase(0, i + 8);    // json暴力解析

				std::u8string jsonconcat{};  // 转换成 utf8
				for (size_t i = 0; i < jsontemp.size(); i++) {
					if (jsontemp[i] != u8'\\') {
						jsonconcat.push_back(jsontemp[i]);
					} else {
						if (i + 5 < jsontemp.size() && jsontemp[i + 1] == u8'u') {
							char16_t temp =
								(char16_t)Utils::Utils::hexChar2dec(jsontemp[i + 2]) * 16 * 16 * 16 +
								(char16_t)Utils::Utils::hexChar2dec(jsontemp[i + 3]) * 16 * 16 +
								(char16_t)Utils::Utils::hexChar2dec(jsontemp[i + 4]) * 16 +
								(char16_t)Utils::Utils::hexChar2dec(jsontemp[i + 5]);
							jsonconcat.append(fast_io::u8concat(fast_io::mnp::code_cvt(std::u16string_view{&temp, 1})));
							i += 5;
						} else {
							if (i + 1 < jsontemp.size()) {
								jsonconcat.push_back(jsontemp[i + 1]);
								i++;
							}
						}
					}
				}
				return jsonconcat;
			}
		}
	} catch (const fast_io::error&) {
	} catch (const std::exception&) {
	}
	return std::u8string{};
}

void translate_asynchronous(std::u8string str, bool isserver, void (*fun)(std::u8string_view original, std::u8string_view res)) noexcept {
	std::thread([=]() { // 必须赋值
		extern bool isRunning;
		if (isRunning && fun) [[likely]] {
			std::u8string translres = translate(str, isserver);
			fun(str, translres);
		}
	}).detach();
}

bool TranslateCommand_onExecute(const fast_io::vector<std::u8string>& args) {
	if (args.size() < 3)
		return false;
	if (args[1] == u8"set") {
		if (args[2] == u8"appid") {
			if (args.size() != 4) return false;
			try {
				appid = fast_io::u8to<std::uint_least64_t>(args[3]);
			} catch (const fast_io::error&) {
				return false;
			}
		} else if (args[2] == u8"key") {
			if (args.size() != 4) return false;
			key = args[3];
		} else {
			if (args.size() != 5) return false;
			if (args[2] == u8"local") {
				local_from = args[3];
				local_to = args[4];
			} else if (args[2] == u8"server") {
				server_from = args[3];
				server_to = args[4];
			} else
				return false;
		}
		switch (SettingManager::languageget) {
		case 0:
		default:
			C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
											 u8"[Helium] ",
											 Utils::TextColor::GREEN,
											 u8"Set successfully!");
			break;
		case 1:
			C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
											 u8"[Helium] ",
											 Utils::TextColor::GREEN,
											 u8"设置成功！");
			break;
		case 2:
			C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
											 u8"[Helium] ",
											 Utils::TextColor::GREEN,
											 u8"設置成功！");
			break;
		case 3:
			C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
											 u8"[Helium] ",
											 Utils::TextColor::GREEN,
											 u8"正常に設定されました！");
			break;
			std::unreachable();
		}
		return true;
	}

	if (appid == 0 || key.empty()) {
		switch (SettingManager::languageget) {
		case 0:
		default:
			C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
											 u8"[Helium] ",
											 Utils::TextColor::RED,
											 u8"Please set appid or key first!");
			break;
		case 1:
			C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
											 u8"[Helium] ",
											 Utils::TextColor::RED,
											 u8"请先设置 appid 或 key！");
			break;
		case 2:
			C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
											 u8"[Helium] ",
											 Utils::TextColor::RED,
											 u8"請先設置 appid 或 key！");
			break;
		case 3:
			C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
											 u8"[Helium] ",
											 Utils::TextColor::RED,
											 u8"最初に appid または key を設定してください！");
			break;
			std::unreachable();
		}
		return true;
	}

	if (args[1] == u8"send" || args[1] == u8"display") {
		std::u8string concatstr{};  // 组合
		for (size_t i = 2; i < args.size(); i++) {
			concatstr.append(args[i]);
			concatstr.push_back(u8' ');
		}
#if 0
		std::u8string translRes = translate(concatstr, false);

		if (!translRes.empty()) {
			if (args[1] == u8"send") {
				print(ServiceMessage, translRes);
			} else {
				switch (SettingManager::languageget) {
				case 0:
				default:
					C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
													 u8"[Helium] ",
													 Utils::TextColor::YELLOW,
													 u8"Translation results: ",
													 Utils::TextColor::RESET,
													 translRes);
					break;
				case 1:
					C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
													 u8"[Helium] ",
													 Utils::TextColor::YELLOW,
													 u8"翻译结果: ",
													 Utils::TextColor::RESET,
													 translRes);
					break;
				case 2:
					C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
													 u8"[Helium] ",
													 Utils::TextColor::YELLOW,
													 u8"翻譯結果: ",
													 Utils::TextColor::RESET,
													 translRes);
					break;
				case 3:
					C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
													 u8"[Helium] ",
													 Utils::TextColor::YELLOW,
													 u8"翻訳結果: ",
													 Utils::TextColor::RESET,
													 translRes);
					break;
					std::unreachable();
				}
			}
			return true;
		}
		//failed
		switch (SettingManager::languageget) {
		case 0:
		default:
			C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
											 u8"[Helium] ",
											 Utils::TextColor::RED,
											 u8"Translation failed!");
			break;
		case 1:
			C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
											 u8"[Helium] ",
											 Utils::TextColor::RED,
											 u8"翻译失败！");
			break;
		case 2:
			C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
											 u8"[Helium] ",
											 Utils::TextColor::RED,
											 u8"請先設置 appid 或 key！");
			break;
		case 3:
			C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
											 u8"[Helium] ",
											 Utils::TextColor::RED,
											 u8"翻訳に失敗しました！");
			break;
			std::unreachable();
		}

#else
		static constexpr auto displayError = []() -> void {
			switch (SettingManager::languageget) {
			case 0:
			default:
				C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
												 u8"[Helium] ",
												 Utils::TextColor::RED,
												 u8"Translation failed!");
				break;
			case 1:
				C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
												 u8"[Helium] ",
												 Utils::TextColor::RED,
												 u8"翻译失败！");
				break;
			case 2:
				C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
												 u8"[Helium] ",
												 Utils::TextColor::RED,
												 u8"請先設置 appid 或 key！");
				break;
			case 3:
				C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
												 u8"[Helium] ",
												 Utils::TextColor::RED,
												 u8"翻訳に失敗しました！");
				break;
				std::unreachable();
			}

		};

		static constexpr void (*send)(std::u8string_view, std::u8string_view) = [](std::u8string_view original, std::u8string_view res) -> void {
			if (res.empty())
				displayError();
			else
				print(ServiceMessage, res);
		};

		static constexpr void (*display)(std::u8string_view, std::u8string_view) = [](std::u8string_view original, std::u8string_view res) -> void {
			if (res.empty())
				displayError();
			else {
				switch (SettingManager::languageget) {
				case 0:
				default:
					C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
													 u8"[Helium] ",
													 Utils::TextColor::YELLOW,
													 u8"Translation results: ",
													 Utils::TextColor::RESET,
													 res);
					break;
				case 1:
					C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
													 u8"[Helium] ",
													 Utils::TextColor::YELLOW,
													 u8"翻译结果: ",
													 Utils::TextColor::RESET,
													 res);
					break;
				case 2:
					C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
													 u8"[Helium] ",
													 Utils::TextColor::YELLOW,
													 u8"翻譯結果: ",
													 Utils::TextColor::RESET,
													 res);
					break;
				case 3:
					C_GuiData::displayClientMessageC(Utils::TextColor::LIGHT_PURPLE,
													 u8"[Helium] ",
													 Utils::TextColor::YELLOW,
													 u8"翻訳結果: ",
													 Utils::TextColor::RESET,
													 res);
					break;
					std::unreachable();
				}
			}
		};

		if (args[1] == u8"send")
			translate_asynchronous(concatstr, false, send);
		else
			translate_asynchronous(concatstr, false, display);
#endif  // 0

		return true;
	} else
		return false;

	return true;
}

fast_io::vector<aliasList_struct> languageto{
	aliasList_struct{stringview_Object{u8"yue", nullptr}},
	aliasList_struct{stringview_Object{u8"kor", nullptr}},
	aliasList_struct{stringview_Object{u8"th", nullptr}},
	aliasList_struct{stringview_Object{u8"pt", nullptr}},
	aliasList_struct{stringview_Object{u8"el", nullptr}},
	aliasList_struct{stringview_Object{u8"bul", nullptr}},
	aliasList_struct{stringview_Object{u8"fin", nullptr}},
	aliasList_struct{stringview_Object{u8"slo", nullptr}},
	aliasList_struct{stringview_Object{u8"cht", nullptr}},
	aliasList_struct{stringview_Object{u8"zh", nullptr}},
	aliasList_struct{stringview_Object{u8"wyw", nullptr}},
	aliasList_struct{stringview_Object{u8"fra", nullptr}},
	aliasList_struct{stringview_Object{u8"ara", nullptr}},
	aliasList_struct{stringview_Object{u8"de", nullptr}},
	aliasList_struct{stringview_Object{u8"nl", nullptr}},
	aliasList_struct{stringview_Object{u8"est", nullptr}},
	aliasList_struct{stringview_Object{u8"cs", nullptr}},
	aliasList_struct{stringview_Object{u8"swe", nullptr}},
	aliasList_struct{stringview_Object{u8"vie", nullptr}},
	aliasList_struct{stringview_Object{u8"en", nullptr}},
	aliasList_struct{stringview_Object{u8"jp", nullptr}},
	aliasList_struct{stringview_Object{u8"spa", nullptr}},
	aliasList_struct{stringview_Object{u8"ru", nullptr}},
	aliasList_struct{stringview_Object{u8"it", nullptr}},
	aliasList_struct{stringview_Object{u8"pl", nullptr}},
	aliasList_struct{stringview_Object{u8"dan", nullptr}},
	aliasList_struct{stringview_Object{u8"rom", nullptr}},
	aliasList_struct{stringview_Object{u8"hu", nullptr}}};

fast_io::vector<aliasList_struct> languagefrom{
	aliasList_struct{stringview_Object{u8"auto", &languageto}},
	aliasList_struct{stringview_Object{u8"yue", &languageto}},
	aliasList_struct{stringview_Object{u8"kor", &languageto}},
	aliasList_struct{stringview_Object{u8"th", &languageto}},
	aliasList_struct{stringview_Object{u8"pt", &languageto}},
	aliasList_struct{stringview_Object{u8"el", &languageto}},
	aliasList_struct{stringview_Object{u8"bul", &languageto}},
	aliasList_struct{stringview_Object{u8"fin", &languageto}},
	aliasList_struct{stringview_Object{u8"slo", &languageto}},
	aliasList_struct{stringview_Object{u8"cht", &languageto}},
	aliasList_struct{stringview_Object{u8"zh", &languageto}},
	aliasList_struct{stringview_Object{u8"wyw", &languageto}},
	aliasList_struct{stringview_Object{u8"fra", &languageto}},
	aliasList_struct{stringview_Object{u8"ara", &languageto}},
	aliasList_struct{stringview_Object{u8"de", &languageto}},
	aliasList_struct{stringview_Object{u8"nl", &languageto}},
	aliasList_struct{stringview_Object{u8"est", &languageto}},
	aliasList_struct{stringview_Object{u8"cs", &languageto}},
	aliasList_struct{stringview_Object{u8"swe", &languageto}},
	aliasList_struct{stringview_Object{u8"vie", &languageto}},
	aliasList_struct{stringview_Object{u8"en", &languageto}},
	aliasList_struct{stringview_Object{u8"jp", &languageto}},
	aliasList_struct{stringview_Object{u8"spa", &languageto}},
	aliasList_struct{stringview_Object{u8"ru", &languageto}},
	aliasList_struct{stringview_Object{u8"it", &languageto}},
	aliasList_struct{stringview_Object{u8"pl", &languageto}},
	aliasList_struct{stringview_Object{u8"dan", &languageto}},
	aliasList_struct{stringview_Object{u8"rom", &languageto}},
	aliasList_struct{stringview_Object{u8"hu", &languageto}}};

fast_io::vector<aliasList_struct> com{
	aliasList_struct{stringview_Object{u8"appid", nullptr}},
	aliasList_struct{stringview_Object{u8"key", nullptr}},
	aliasList_struct{stringview_Object{u8"local", &languagefrom}},
	aliasList_struct{stringview_Object{u8"server", &languagefrom}}};

ICommand TranslateCommand{
	u8"translate",
	u8".translate or .transl [set [[loacl, server] <from> <to>, appid <appid>, key <key>], send <message>, display <message>]",
	{u8"Translate with Baidu Translator", u8"使用百度翻译器翻译", u8"使用百度翻譯器翻譯", u8"Baidu Translator で翻訳する"},
	{u8"transl"},
	fast_io::vector<aliasList_struct>{aliasList_struct{stringview_Object{u8"set", &com}},
									  aliasList_struct{stringview_Object{u8"send", nullptr}},
									  aliasList_struct{stringview_Object{u8"display", nullptr}}},  // If empty must use fast_io::vector<aliasList_struct>{}
	nullptr,
	&TranslateCommand_onExecute};

